<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Content-Language" content="zh-CN"><link href="stylesheet.css" media="all" rel="stylesheet" type="text/css">
<title>报告服务器里的错误</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head><body class="SECT1">
<div>
<table summary="Header navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><th colspan="5" align="center" valign="bottom">PostgreSQL 8.2.3 中文文档</th></tr>
<tr><td width="10%" align="left" valign="top"><a href="source-format.html" accesskey="P">后退</a></td><td width="10%" align="left" valign="top"><a href="source.html">快退</a></td><td width="60%" align="center" valign="bottom">章45. PostgreSQL 编码约定</td><td width="10%" align="right" valign="top"><a href="source.html">快进</a></td><td width="10%" align="right" valign="top"><a href="error-style-guide.html" accesskey="N">前进</a></td></tr>
</table>
<hr align="LEFT" width="100%"></div>
<div class="SECT1"><h1 class="SECT1"><a name="ERROR-MESSAGE-REPORTING">45.2. 报告服务器里的错误</a></h1><a name="AEN68172"></a><a name="AEN68174"></a>
<p>在服务器代码里生成的错误，警告以及日志信息应该用 <code class="FUNCTION">ereport</code> 或者它的老前辈 <code class="FUNCTION">elog</code> 创建。这个函数的使用已经复杂得足够做些解释了。</p>
<p>每条消息都有两个必须的要素：一个严重级别(范围从 <tt class="LITERAL">DEBUG</tt> 到 <tt class="LITERAL">PANIC</tt>)和一个主要消息文本。除此之外还有可选的元素，最常见的就是一个遵循 SQL 标准的 SQLSTATE 习惯的错误标识码。<code class="FUNCTION">ereport</code> 本身只是一个壳函数，它的存在主要是为了便于让消息生成看起来像 C 代码里的函数调用。<code class="FUNCTION">ereport</code> 直接接受的唯一参数是严重级别。主消息文本和任何附加消息元素都是通过在 <code class="FUNCTION">ereport</code> 调用里调用辅助函数(比如 <code class="FUNCTION">errmsg</code>)生成的。</p>
<p>典型的调用 <code class="FUNCTION">ereport</code> 的方式看起来可能像下面这样：</p>
<pre class="PROGRAMLISTING">ereport(ERROR,
        (errcode(ERRCODE_DIVISION_BY_ZERO),
         errmsg("division by zero")));</pre>
<p>这样就声明了严重级别 <tt class="LITERAL">ERROR</tt>(一个错误)。调用 <code class="FUNCTION">errcode</code> 则使用一个定义在 <tt class="FILENAME">src/include/utils/errcodes.h</tt> 里面的宏声明 SQLSTATE 错误代码。<code class="FUNCTION">errmsg</code> 调用提供主要的消息文本。请注意额外的圆括弧包围在辅助函数调用周围，这么做虽然烦人，但是语法上是必须的。</p>
<p>然后是一个更复杂的例子：</p>
<pre class="PROGRAMLISTING">ereport(ERROR,
        (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
         errmsg("function %s is not unique",
                func_signature_string(funcname, nargs,
                                      actual_arg_types)),
         errhint("Unable to choose a best candidate function. "
                 "You may need to add explicit typecasts.")));</pre>
<p>这个例子演示了使用格式化代码把运行时数值嵌入一个消息文本的用法。同样，还提供了一个可选的"暗示"信息。</p>
<p><code class="FUNCTION">ereport</code> 可用的附属过程有：</p>
<ul>
<li><p><code class="FUNCTION">errcode(sqlerrcode)</code> 为该条件声明 SQLSTATE 错误标识符代码。如果没有调用这个过程，并且错误严重级别是 <tt class="LITERAL">ERROR</tt> 或更高，那么错误标识符缺省是 <tt class="LITERAL">ERRCODE_INTERNAL_ERROR</tt> ，如果错误严重级别是 <tt class="LITERAL">WARNING</tt> 则为 <tt class="LITERAL">ERRCODE_WARNING</tt> ，否则(用于 <tt class="LITERAL">NOTICE</tt> 或者更低级别)为 <tt class="LITERAL">ERRCODE_SUCCESSFUL_COMPLETION</tt> 。虽然这些缺省都很方便，但是最好还是在省略 <code class="FUNCTION">errcode()</code> 调用之前三思。</p></li>
<li><p><code class="FUNCTION">errmsg(const char *msg, ...)</code> 声明主错误消息文本，以及可能的插入其中的运行时数值。插入是使用 <code class="FUNCTION">sprintf</code> 风格的格式代码插入的。除了 <code class="FUNCTION">sprintf</code> 接受的标准格式代码，还接受 <tt class="LITERAL">%m</tt> 用于插入 <code class="FUNCTION">strerror</code> 为当前 <tt class="LITERAL">errno</tt> 值返回的错误信息。<a name="AEN68217" href="error-message-reporting.html#FTN.AEN68217"><span class="footnote">[1]</span></a> &nbsp; <tt class="LITERAL">%m</tt> 并不要求在 <code class="FUNCTION">errmsg</code> 的参数列表里有任何对应的项目。请注意这个消息字符串在格式代码得到处理之前将不会通过 <code class="FUNCTION">gettext</code> 运行获取合适的本地化。</p></li>
<li><p><code class="FUNCTION">errmsg_internal(const char *msg, ...)</code> 和 <code class="FUNCTION">errmsg</code> 一样，只是消息字符串将不会包含在国际化消息字典里。这个函数应该用于"不可能发生"的情况，也就是不值得展开进行翻译的场合。</p></li>
<li><p><code class="FUNCTION">errdetail(const char *msg, ...)</code> 提供一个可选的"详细"信息；在存在额外的的信息，并且很适合放在主消息里面的时候使用这个函数。消息字符串处理的方法和 <code class="FUNCTION">errmsg</code> 完全一样。</p></li>
<li><p><code class="FUNCTION">errhint(const char *msg, ...)</code> 提供一个可选的"暗示"消息；这个函数用于提供如何修补问题的建议，而不是提供错误的事实。消息字符串处理的方式和 <code class="FUNCTION">errmsg</code> 一样。</p></li>
<li><p><code class="FUNCTION">errcontext(const char *msg, ...)</code> 通常不会直接从 <code class="FUNCTION">ereport</code> 消息点里直接调用；而是用在 <tt class="LITERAL">error_context_stack</tt> 回调函数里提供有关错误发生的环境的信息，比如，当前的位置是在一个 PL 函数里等等。消息字符串的处理和 <code class="FUNCTION">errmsg</code> 完全一样。和其它辅助函数不同，这个函数在一次 <code class="FUNCTION">ereport</code> 调用里可以调用多次；随后的调用生成的字符串将带着各自的换行符连接在原来的字符串上。</p></li>
<li><p><code class="FUNCTION">errposition(int cursorpos)</code> 声明一个错误在查询字符串里的文本位置。目前它只是在汇报查询处理过程中的词法和语法分析阶段检测到的错误有用。</p></li>
<li><p><code class="FUNCTION">errcode_for_file_access()</code> 是一个便利函数，它可以为一个文件访问类的系统调用选择一个合适的 SQLSTATE 错误标识符。它利用保存下来的 <tt class="LITERAL">errno</tt> 判断生成哪个错误代码。通常它应该和主消息文本里的 <tt class="LITERAL">%m</tt> 结合使用。</p></li>
<li><p><code class="FUNCTION">errcode_for_socket_access()</code> 是一个便利函数，它可以为一个套接字相关的系统调用选择一个合适的 SQLSTATE 错误标识符。</p></li>
</ul>
<p>还有一个老一些的 <code class="FUNCTION">elog</code> 函数，仍然在频繁使用。一个 <code class="FUNCTION">elog</code> 调用</p>
<pre class="PROGRAMLISTING">elog(level, "format string", ...);</pre>
<p>完全等效于</p>
<pre class="PROGRAMLISTING">ereport(level, (errmsg_internal("format string", ...)));</pre>
<p>请注意 SQLSTATE 错误代码总是缺省的，并且消息字符串并没有包含在国际化信息字典里。因此，<code class="FUNCTION">elog</code> 应该只用于内部错误以及低层的调试日志。任何普通用户感兴趣的消息都应该通过 <code class="FUNCTION">ereport</code> 生成。当然，还有大量内部的"不可能发生"的错误检查使用 <code class="FUNCTION">elog</code> ；因为这些信息最好还是表示得简单些好。</p>
<p>书写好的错误消息的建议可以在<a href="error-style-guide.html">节45.3</a>找到。</p>
</div>
<h3 class="FOOTNOTES">注意</h3>
<table border="0" class="FOOTNOTES" width="100%">
<tr><td align="LEFT" valign="TOP" width="5%"><a name="FTN.AEN68217" href="error-message-reporting.html#AEN68217"><span class="footnote">[1]</span></a></td><td align="LEFT" valign="TOP" width="95%"><p>也就是说，在到达 <code class="FUNCTION">ereport</code> 调用的时候当前的数值；在附属报告过程里对 <tt class="LITERAL">errno</tt> 的修改将不会影响他。但是如果你在 <tt class="LITERAL">strerror(errno)</tt> 的参数列表里明确地写 <code class="FUNCTION">errmsg</code> ，这一点就不能保证了，因此，请不要这么做。</p></td></tr>
</table>
<div>
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td width="33%" align="left" valign="top"><a href="source-format.html" accesskey="P">后退</a></td><td width="34%" align="center" valign="top"><a href="index.html" accesskey="H">首页</a></td><td width="33%" align="right" valign="top"><a href="error-style-guide.html" accesskey="N">前进</a></td></tr>
<tr><td width="33%" align="left" valign="top">格式</td><td width="34%" align="center" valign="top"><a href="source.html" accesskey="U">上一级</a></td><td width="33%" align="right" valign="top">错误消息风格指导</td></tr>
</table>
</div>
</body></html>